summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt
blob: 9076a86c41dacb285e9c120eeb8d362b058a6938 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

package org.yuzu.yuzu_emu.utils

import android.app.ActivityManager
import android.content.Context
import android.os.Build
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import java.util.Locale
import kotlin.math.ceil

object MemoryUtil {
    private val context get() = YuzuApplication.appContext

    private val Float.hundredths: String
        get() = String.format(Locale.ROOT, "%.2f", this)

    // Required total system memory
    const val REQUIRED_MEMORY = 8

    const val Kb: Float = 1024F
    const val Mb = Kb * 1024
    const val Gb = Mb * 1024
    const val Tb = Gb * 1024
    const val Pb = Tb * 1024
    const val Eb = Pb * 1024

    private fun bytesToSizeUnit(size: Float, roundUp: Boolean = false): String =
        when {
            size < Kb -> {
                context.getString(
                    R.string.memory_formatted,
                    size.hundredths,
                    context.getString(R.string.memory_byte)
                )
            }
            size < Mb -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Kb) else (size / Kb).hundredths,
                    context.getString(R.string.memory_kilobyte)
                )
            }
            size < Gb -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Mb) else (size / Mb).hundredths,
                    context.getString(R.string.memory_megabyte)
                )
            }
            size < Tb -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Gb) else (size / Gb).hundredths,
                    context.getString(R.string.memory_gigabyte)
                )
            }
            size < Pb -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Tb) else (size / Tb).hundredths,
                    context.getString(R.string.memory_terabyte)
                )
            }
            size < Eb -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Pb) else (size / Pb).hundredths,
                    context.getString(R.string.memory_petabyte)
                )
            }
            else -> {
                context.getString(
                    R.string.memory_formatted,
                    if (roundUp) ceil(size / Eb) else (size / Eb).hundredths,
                    context.getString(R.string.memory_exabyte)
                )
            }
        }

    val totalMemory: Float
        get() {
            val memInfo = ActivityManager.MemoryInfo()
            with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
                getMemoryInfo(memInfo)
            }

            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
                memInfo.advertisedMem.toFloat()
            } else {
                memInfo.totalMem.toFloat()
            }
        }

    fun isLessThan(minimum: Int, size: Float): Boolean =
        when (size) {
            Kb -> totalMemory < Mb && totalMemory < minimum
            Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
            Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
            Tb -> totalMemory < Pb && (totalMemory / Tb) < minimum
            Pb -> totalMemory < Eb && (totalMemory / Pb) < minimum
            Eb -> totalMemory / Eb < minimum
            else -> totalMemory < Kb && totalMemory < minimum
        }

    // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
    // the potential error created by memInfo.totalMem
    fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory, true)
}